/*
 *      Document   : html5cdm-v2.0
 *      Created on : Jul 6, 2013, 12:09:51 AM
 *      Author     : Hoang Giang <hoanggv.neu att gmail dot com>
 */

/// CDM Context Dispatcher
var CDMContextIndex = 0;
var CDMDispatcher = []; // Array of CCPairs
var CDMResources = []; // Array of Resources
var AcceptedPeers = [];

var origin = location.protocol
		+ "//"
		+ window.location.hostname
		+ ((window.document.location.port == "") ? "" : ":"
				+ window.document.location.port);

function processMessage(e) {
	if (!accepted(e.origin)) {
		console.log("not allowed");
		return;
	}

	var data;
	try {
		data = JSON.parse(e.data);
	} catch (err) {
		console.log(err.message);
		console.log("Warning! Not a Restful CDM message");
		Xdm5.sendCdmMsg(e.source, e.origin, "don't like Restful CDM?");
		return;
	}

	if (data.statusCode) {
		// Process a response
		if (!dispatchResponse(data))
			console.log("No callback found!");
	} else {
		// Process a request
		if (!dispatchRequest(data, e))
			Xdm5.sendCdmMsg(e.source, e.origin, new RestfulCDMResponse(404,
					"resource not found", data.context));
	}
}

function dispatchRequest(request, e) {
	for ( var i = 0; i < CDMResources.length; i++) {
		if (request.resourceUri == CDMResources[i].path) {
			CDMResources[i].handler(request, e);
			return true;
		}
	}
	return false;
}

function dispatchResponse(data) {
	for ( var i = 0; i < CDMDispatcher.length; i++) {
		if (data.context == CDMDispatcher[i].context) {
			CDMDispatcher[i].cb(data);
			// CDMDispatcher.splice(i,1);
			return true;
		}
	}
	return false;
}

function accepted(origin) {
	for ( var i = 0; i < AcceptedPeers.length; i++) {
		if ((AcceptedPeers[i] === origin) || origin.match(AcceptedPeers[i]))
			return true;
	}
	return false;
}

function CCPair(context, cb) {
	this.context = context;
	this.cb = cb;
}

function Resource(path, handler) {
	this.path = path;
	this.handler = handler;
}

function RestfulCDMRequest(method, resourceUri, payload, context) {
	this.method = method;
	this.resourceUri = resourceUri;
	this.payload = payload;
	this.context = context;
}

function RestfulCDMResponse(statusCode, payload, context) {
	this.statusCode = statusCode;
	this.payload = payload;
	this.context = context;
}

var REST = {
	PUT : "PUT",
	GET : "GET",
	POST : "POST",
	DELETE : "DELETE"
};

var Xdm5 = {
	origin : origin,
	response : function(statusCode, payload, context) {
		return new RestfulCDMResponse(statusCode, payload, context);
	},
	createGetRequest : function(resourceUri, context) {
		return new RestfulCDMRequest(REST.GET, resourceUri, null, context);
	},
	createPostRequest : function(resourceUri, payload, context) {
		return new RestfulCDMRequest(REST.POST, resourceUri, payload, context);
	},
	createPutRequest : function(resourceUri, payload, context) {
		return new RestfulCDMRequest(REST.PUT, resourceUri, payload, context);
	},
	createDeleteRequest : function(resourceUri, context) {
		return new RestfulCDMRequest(REST.DELETE, resourceUri, null, context);
	},
	registerPeer : function(peer) {
		if (typeof peer != 'string')
			throw "PeerRegisteringException";
		else if (peer.indexOf("http") === -1) {
			var peerOrig = document.getElementById(peer).contentWindow.origin;
			if (typeof peerOrig == 'undefined')
				throw "PeerRegisteringException";
			AcceptedPeers.push(peerOrig);
		} else
			AcceptedPeers.push(peer);
	},
	deletePeer : function(peer) {
		for ( var i = 0; i < AcceptedPeers.length; i++) {
			if (AcceptedPeers[i] === peer) {
				AcceptedPeers.splice(i, 1);
			}
		}
	},
	registerResource : function(path, handler) {
		CDMResources.push(new Resource(path, handler));
	},
	onResponse : function(cb) {
		CDMContextIndex++;
		if (cb != null)
			CDMDispatcher.push(new CCPair(CDMContextIndex, cb));
		return CDMContextIndex;
	},
	sendCdmMsg : function(destWindow, destOrigin, msg) {
		if (!msg.context)
			console.log("Warning! No context/callback identified");

		if (typeof destWindow == 'string')
			destWindow = document.getElementById(destWindow).contentWindow;
		destWindow.postMessage(JSON.stringify(msg), destOrigin);
	}
};

window.ActiveXObject ? window.attachEvent("onmessage", processMessage, true)
		: window.addEventListener("message", processMessage, true);